﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Threading;

namespace Jenvin.Library.Threading
{
    /// <summary>
    /// 用Void类型 ，表示参数 无返回值的情况 。
    /// c# 关键字 void 不能当做类型参数 
    /// </summary>
    public class Void
    {
        private Void()
        {

        }
        static Void()
        {
            Value = new Void();
        }
        public static Void Value { get; private set; }
    }

    /// <summary>
    /// 继承此接口。表示包装一个异步方法或一系列异步方法。Execute 开始执行异步方法
    /// </summary>
    public interface IAsync
    {
        /// <summary>
        /// Execute 开始执行异步方法
        /// </summary>
        /// <param name="cont">通常为执异步方法的下一步动作</param>
        void Execute(Action cont);
    }
    /// <summary>
    /// 代表一个返回值为T的异步操作。如果异步操作没不返回值。用 class Void代替
    /// </summary>
    public class Async<T> : IAsync
    {
        protected T result;
        protected bool completed = false;
        protected Action<Action<T>> m_func = null;
        public T Result
        {
            get
            {
                if (!completed)
                    throw new Exception("操作没有完成，确定是否正确调用了 'yield return'");
                return result;
            }
        }

        public Async(Action<Action<T>> func)
        {
            m_func = func;
        }
        /// <summary>
        /// 他表示一个结果 没有任何操作但
        /// </summary>
        /// <param name="cont"></param>
        public virtual void Execute(Action cont)
        {
            m_func((res) =>
            {
                result = res;
                completed = true;
                cont();
            });
            return;
        }
    }

    /// <summary>
    /// 表示一个原生的异步操作。是不一对BeginXXX,EndXXX 的操作。
    /// 当Execute调用后BeginXXX开始调用。一个异步操作。操作完成后执行回调。
    /// 并调用 cont
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class AsyncPrimitive<T> : Async<T>
    {

        public AsyncPrimitive(Func<AsyncCallback, object, IAsyncResult> begin, Func<IAsyncResult, T> end)
            : base((cont) => begin(delegate(IAsyncResult res) { cont(end(res)); }, null))
        {
            //指定Begin函数。和Begin的回调委托。在回调委托中调用end取得结果。并把接下的操作委托结 cont

            //this.func = (cont) => begin(delegate(IAsyncResult res) { cont(end(res)); }, null);
        }

        public override void Execute(Action cont)
        {
            //这里实际上是调用Begin。传入function.为回调后取得结果后。
            this.m_func((res) =>
            {

                result = res;//res 是 end后的结果 
                completed = true;//已经完成
                cont();//继续下一下异步
            });
        }
    }
    /// <summary>
    /// 一系列异步操作的最终返回结果。典型的情况就是循环从IO读数据，当所有数据读完后。
    /// 当所有操作完成后从Result属性取得结果  
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class AsyncWithResult<T> : Async<T>
    {
        IEnumerable<IAsync> en;
        public AsyncWithResult(IEnumerable<IAsync> async)
            : base(null)
        {
            en = async;
        }

        public override void Execute(Action cont)
        {
            Async.Run<T>(en.GetEnumerator(), (res) =>
            {
                completed = true;
                result = res;
                cont();
            });
        }
    }

    /// <summary>
    /// 一系列异步操作。最终操作完成 不需要 返回任何结果 
    /// </summary>
    public class AsyncWithVoidResult : Async<Void>
    {
        IEnumerable<IAsync> en;

        public AsyncWithVoidResult(IEnumerable<IAsync> async)
            : base(null)
        {
            en = async;
            result = Void.Value;
        }

        public override void Execute(Action cont)
        {
            Async.Run(en.GetEnumerator(), () =>
            {
                completed = true;
                cont();
            });
        }
    }

    /// <summary>
    /// 所有被 包装的异步方法。都由Async中的静态方法发起
    /// </summary>
    public static class Async
    {
        /// <summary>
        ///将一串 异步方法，连接 起来，并行执行
        /// </summary>
        public static IEnumerable<IAsync> Parallel(params IEnumerable<IAsync>[] ops)
        {
            yield return new Async<Void>((cont) =>
             {
                 bool[] completed = new bool[ops.Length];
                 for (int i = 0; i < ops.Length; i++)
                     Set(ops[i], completed, i, cont).Start();
             });
        }

        private static IEnumerable<IAsync> Set(IEnumerable<IAsync> op, bool[] flags, int index, Action<Void> cont)
        {
            foreach (IAsync async in op) yield return async;
            bool allSet = true;
            lock (flags)
            {
                flags[index] = true;
                foreach (bool b in flags) if (!b) { allSet = false; break; }
            }
            if (allSet) cont(Void.Value);
        }


        /// <summary>
        /// 等待一系列异步操作,完成
        ///</summary>
        /// <param name="async"></param>
        public static void Wait(this IEnumerable<IAsync> asyncs)
        {
            ManualResetEvent wh = new ManualResetEvent(false);
            Async.Run(asyncs.GetEnumerator(),
                () => wh.Set());
            wh.WaitOne();
        }


        /// <summary>
        /// 执行一系列异步操作。没有返回结果 
        /// </summary>
        /// <param name="async"></param>
        public static void Start(this IEnumerable<IAsync> asyncs)
        {
            Async.Run(asyncs.GetEnumerator());
        }

        /// <summary>
        /// 执行一系列异步。在另一个异步操作的方法中 
        /// <param name="async"></param>
        /// </summary>
        /// <typeparam name="T">返回值类型</typeparam>
        public static Async<T> StartAsync<T>(this IEnumerable<IAsync> asyncs)
        {
            return new AsyncWithResult<T>(asyncs);
        }

        /// <summary>
        ///执行一系列异步。在另一个异步操作的方法中 。没有返回值
        /// </summary>
        public static Async<Void> StartAsync(this IEnumerable<IAsync> asyncs)
        {
            return new AsyncWithVoidResult(asyncs);
        }

        #region Implementation

        internal static void Run<T>(IEnumerator<IAsync> en, Action<T> cont)
        {
            Async<T> prev = en.Current as Async<T>;

            if (!en.MoveNext())
            {
                if (prev != null)
                {
                    cont(prev.Result);
                }
                else
                {
                    cont(default(T));
                }
                return;
            }
            en.Current.Execute
                (() => Async.Run<T>(en, cont));
        }

        internal static void Run(IEnumerator<IAsync> en, Action cont)
        {
            if (!en.MoveNext()) { cont(); return; }
            en.Current.Execute
                (() => Async.Run(en, cont));
        }

        internal static void Run(IEnumerator<IAsync> en)
        {
            if (!en.MoveNext()) return;
            en.Current.Execute
                (() => Async.Run(en));
        }

        #endregion
    }
}
